#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <string.h>

// 字符串就是保存多个ASCII码字符的容器。用char数组来保存， 以0(也可以表示'\0',)结束。
// 比如"str"字符串，他的实际空间为 {'s', 't', 'r', '\0'} 一共4字节。
// 要操作字符串需要包含C标准库<string.h>
// 几个常见的字符串操作。
// strlen 获取字符串长度。去掉0的字符串长度。
// strcpy 拷贝。
// strcmp 比较。
// strcat 拼接两个字符串。
// strchr 查找一个字符
// strstr 查找一个字符串
// strtok 切分字符串。
// 操作出界可能会崩溃。

char globalStringA[128];
char globalStringB[128];

void check_strcpy()
{
    printf("[%s,%d]check strcpy ---------------->\n", __FILE__, __LINE__);
    // size_t 是 unsigned long 类型。
    for (size_t i = 0; i < sizeof(globalStringA); i++)
    {
        // 将字符数组全部初始化为'a'
        globalStringA[i] = 'a';
    }
    // 将"check copy"拷贝到字符数组globalStringA中。包括结束符'\0'
    // 第一个参数必须是字符数组，如果是字符串常量，是不行的。
    // 第一个参数必须有足够的空间保存第二个字符串参数，不然可能崩溃。
    strcpy(globalStringA, "check copy");
    printf("[%s,%d]string value=%s\n", __FILE__, __LINE__, globalStringA);
}

void check_strlen()
{
    printf("[%s,%d]check strlen ---------------->\n", __FILE__, __LINE__);
    // 将字符串拷贝到globalStringA中。
    strcpy(globalStringA, "check length");
    int tmplen = strlen(globalStringA);
    printf("[%s,%d]string value=%s,size=%d,buffer size=%lu\n", __FILE__, __LINE__, globalStringA, tmplen, sizeof(globalStringA));
}

void check_strcmp()
{
    printf("[%s,%d]check strcmp ---------------->\n", __FILE__, __LINE__);
    // strcmp从第一个字符开始比较大小(字符数组数据直接二进制对比)，直到某个字符串结束'\0'.
    // >0 表示第一个大于第二个，<0表示第一个小于第二个，==0表示字符串一样。
    int compareflag = strcmp("str1", "str2");
    printf("[%s,%d]compare result=%d\n", __FILE__, __LINE__, compareflag);
}

void check_strcat()
{
    printf("[%s,%d]check strcat ---------------->\n", __FILE__, __LINE__);
    strcpy(globalStringA, "str1");
    // 将第二个字符串拼接到第一个字符数组中，第一个字符数组结束符'\0'开始拼接(不是'\0'下个字符)。
    // 第一个参数必须有足够的空间保存拼接后的字符串，否则可能崩溃。
    strcat(globalStringA, "str2");
    printf("[%s,%d]string cat result=%s\n", __FILE__, __LINE__, globalStringA);
}

void check_strchr()
{
    printf("[%s,%d]check strchr ---------------->\n", __FILE__, __LINE__);
    strcpy(globalStringA, "check strchr");
    // 查找globalStringA字符串中，第一个字符's'的首地址，并返回给tmppointor。没有找到返回NULL。
    char *tmppointor = strchr(globalStringA, 's');
    printf("[%s,%d]find string=%s, find sub string=%s\n", __FILE__, __LINE__, globalStringA, tmppointor);
}

void check_strstr()
{
    printf("[%s,%d]check strstr ---------------->\n", __FILE__, __LINE__);
    strcpy(globalStringA, "check strstr");
    // 查找globalStringA字符串中，第一个字符串"str"的首地址，并返回给tmppointor。没有找到返回NULL。
    char *tmppointor = strstr(globalStringA, "str");
    printf("[%s,%d]find string=%s, find sub string=%s\n", __FILE__, __LINE__, globalStringA, tmppointor);
}

void check_strtok()
{
    printf("[%s,%d]check strtok ---------------->\n", __FILE__, __LINE__);
    memset(globalStringA, 0, sizeof(globalStringA));
    strcpy(globalStringA, "str1*&^str2*&^str3");
    // 
    const char *tmpTokStr = "*&^";//"*&^";"xxx";
    //用tmpTokStr字符串切割globalStringA字符串。返回切割后的第一个地址。如果原始字符串globalStringA没有切割字符串tmpTokStr，返回原始字符串。
    // 如果原始字符串globalStringA有切割字符串tmpTokStr。tmppointor得到切割后的第一个地址。
    // strtok是在原始字符串globalStringA上操作，会将切割字符串位置的数据替换成0
    char *tmppointor = strtok(globalStringA, tmpTokStr);

    do
    {
        if(tmppointor == NULL)
        {
            break;
        }

        printf("[%s,%d]printf origin string\n", __FILE__, __LINE__);
        for(size_t i = 0; i < sizeof(globalStringA); /*i++在循环内部做，这里不需要++*/)
        {
            printf("0x%02x ", globalStringA[i++]);//i++，本条语句不会加，本条语句完成再加。
            if((i % 32) == 0)
            {
                printf("\n");
            }
        }

        printf("[%s,%d]origin string=%s, sub tok string=%s\n", __FILE__, __LINE__, globalStringA, tmppointor);
        tmppointor = strtok(NULL, tmpTokStr);
    }while(1);
}


int main(int argc, char **argv)
{
    check_strcpy();
    check_strlen();
    check_strcmp();
    check_strcat();
    check_strchr();
    check_strstr();
    check_strtok();
    return 1;
}
